(function () {
	var ns = ij.pkg('core').namespaceString;
	ij.core.Observable = ij.core.Object.extend({
		init: function (config) {
			return this._super(ij.apply({
				classname: ns + '.Observable',
				listeners: {},
				supressEvents: false
			}, config));
		},
		bind: function (eventName, listener, scope) {
			listener = scope?{
				callback: listener,
				scope: scope
			}:listener;
			if (this.listeners[eventName]) {
				this.listeners[eventName].push(listener);
			} else {
				this.listeners[eventName] = [listener];
			}
			
			return this;
		},
		unbind: function (eventName, listener) {
			if (this.listeners[eventName]) {
				this.listeners.each(function (i, item) {
					if (item === listener || (typeof item == 'object' && item.callback === listener)) {
						this.listeners[eventName].splice(i, 1);
					}
				}, this);
			}
			
			return this;
		},
		dispatchEvent: function (event, listener) {
			if (this.supressEvents) {
				return this;
			}
			if (typeof event == 'string') {
				event = new ij.core.Event({
					name: event
				});
			}
			event.dispatcher = this;
			var callback = function (i, listener) {
				var callback = listener,
				scope = this;
				if (typeof listener == 'object') {
					callback = listener.callback;
					scope = listener.scope || scope;
				}
				
				callback.call(scope, event);
				
				return !event.propagationStopped;
			};
			if (listener) {
				callback.call(this, null, listener);
			}
			if (event && this.listeners[event.name]) {
				this.listeners[event.name].each(callback, this);
			}
			
			return this;
		},
		load: function (url) {
			this._super(url, function (data) {
				if (data) {
					this.dispatchEvent('load');
				} else {
					this.dispatchEvent('loadError');
				}
			}, this);
			
			return this;
		}
	});
})();
